#pragma once

#include <glibmm.h>

#include "TmpAllocator.hpp"
#include "GObjHelpers.hpp"

namespace BuildNG
{
  class IDirectoryTree
  {
  public:
    class DirIt : public Object
    {
    public:
      virtual ~DirIt(){}
      virtual bool move_next() = 0;
      virtual const Glib::ustring& get_cur() = 0;
      virtual bool is_directory() = 0;
    };

    virtual Glib::RefPtr<DirIt> get_dir_iterator(const Glib::ustring &path) const = 0;
    virtual Glib::ustring get_root() const = 0;
    virtual Glib::ustring get_cur_dir() const = 0;
  };

  enum SuperGlobFlags
  {
    SuperGlobFlag_AbsolutePath      = (1 << 0),
  };

  std::vector<Glib::ustring> super_glob(const Glib::ustring &pattern,const IDirectoryTree &dir_tree,int flags = 0);
  std::vector<Glib::ustring> super_glob(const Glib::ustring &pattern,const Glib::ustring &base_dir,int flags = 0);

  ////////////
  // Internal stuff. Exposed here for the unit testing.
  struct GlobToken
  {
    const gchar *begin;
    const gchar *end;
    bool is_wildcard;

    bool operator == (const gchar *b) const;
  };
  void tokenize_glob_pattern(const gchar *pattern,TmpArray<GlobToken> &out);
  bool glob_compare(const Glib::ustring &pattern,const Glib::ustring &b);

  class PhysDirTree : public IDirectoryTree
  {
  public:
    PhysDirTree(const Glib::ustring &cur_dir);
    
    virtual Glib::RefPtr<DirIt> get_dir_iterator(const Glib::ustring &path) const;
    virtual Glib::ustring get_root() const;
    virtual Glib::ustring get_cur_dir() const;
    
    class PhysDirTreeIt : public DirIt
    {
    public:
      PhysDirTreeIt(const Glib::ustring &path);

      virtual bool move_next();
      virtual const Glib::ustring& get_cur();
      virtual bool is_directory();

    private:
      Glib::Dir dir;
      Glib::DirIterator it;
      Glib::ustring cur_value;
      
      enum State
      {
        State_NotInitiated,
        State_Valid,
        State_Ended,
      };
      State state;
    };

  private:
    Glib::ustring cur_dir;
  };
}
